using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using System.IO;

namespace VideoSample
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        Video video;
        VideoPlayer videoPlayer;
        Vector2 videoDimensions;

        SpriteFont spriteFont;

        int mode = 0;
        string[] modeStrings;

        Effect postProcessEffect;

        Model sphereModel;

        GamePadState currentGamepadState;
        KeyboardState currentKeyboardState;
        GamePadState lastGamepadState;
        KeyboardState lastKeyboardState;
        private Texture2D videoTex;
        private int fileNum = -1;
        private int frameCounter = 0;
        Vector2 screenDim;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";

            modeStrings = new string[4];
            modeStrings[0] = "Normal Dimensions";
            modeStrings[1] = "Fullscreen";
            modeStrings[2] = "Post Processing: Negative + Distorsion";
            modeStrings[3] = "On a Sphere";

        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here

            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);
            video = Content.Load<Video>("bad apple");
            videoDimensions = new Vector2(video.Width, video.Height);

            videoPlayer = new VideoPlayer();
            videoPlayer.Play(video);

            spriteFont = Content.Load<SpriteFont>("text");
            postProcessEffect = Content.Load<Effect>("PostProcessNoise");
            sphereModel = Content.Load<Model>("Sphere");
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            frameCounter = (frameCounter + 1)%61;

            lastGamepadState = currentGamepadState;
            lastKeyboardState = currentKeyboardState;

            currentKeyboardState = Keyboard.GetState();
            currentGamepadState = GamePad.GetState(PlayerIndex.One);

            if ((currentGamepadState.Buttons.A == ButtonState.Pressed && lastGamepadState.Buttons.A == ButtonState.Released) ||
                (currentKeyboardState.IsKeyDown(Keys.Space) && lastKeyboardState.IsKeyUp(Keys.Space)))
                mode = (mode + 1) % 4;

            if ((currentGamepadState.Buttons.X == ButtonState.Pressed && lastGamepadState.Buttons.X == ButtonState.Released) ||
                (currentKeyboardState.IsKeyDown(Keys.P) && lastKeyboardState.IsKeyUp(Keys.P)))
            {
                if (videoPlayer.State == MediaState.Playing)
                    videoPlayer.Pause();
                else
                    videoPlayer.Resume();
            }

            screenDim = new Vector2(GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height);

            videoTex = videoPlayer.GetTexture();
            if (videoPlayer.State==MediaState.Stopped)
            {
                this.Exit();
            }
            if (videoTex!=null)
            {
                Color[] data = new Color[videoTex.Height * videoTex.Width];

                videoTex.GetData<Color>(data);

                if (frameCounter % 10 == 0)
                {
                    fileNum++;
                    SaveColorToFile("..\\..\\..\\output\\x" + fileNum + ".txt", data, videoTex.Height, videoTex.Width);
                }
            }

            base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            //GraphicsDevice.Clear(Color.CornflowerBlue);



            //;
            //spriteBatch.Begin();
            //spriteBatch.DrawString(spriteFont, modeStrings[mode], new Vector2(20, 20), Color.Black);
            //spriteBatch.DrawString(spriteFont, modeStrings[mode], new Vector2(21, 21), Color.Gold);

            //spriteBatch.DrawString(spriteFont, "[Space] / GamePad A - Change Mode", new Vector2(20, screenDim.Y - 60), Color.Black);
            //spriteBatch.DrawString(spriteFont, "[Space] / GamePad A - Change Mode", new Vector2(21, screenDim.Y - 59), Color.Gold);

            //spriteBatch.DrawString(spriteFont, "[P] / GamePad X - Pause / Resume", new Vector2(20, screenDim.Y - 40), Color.Black);
            //spriteBatch.DrawString(spriteFont, "[P] / GamePad X - Pause / Resume", new Vector2(21, screenDim.Y - 39), Color.Gold);

            //spriteBatch.End();

 

           // base.Draw(gameTime);
        }

        public void DrawMovie(GameTime gameTime)
        {
            switch (mode)
            {
                case 0:
                    spriteBatch.Begin();
                    spriteBatch.Draw(videoTex, 0.5f * screenDim - 0.5f * videoDimensions, Color.White);
                    spriteBatch.End();
                    break;
                case 1:
                    spriteBatch.Begin();
                    spriteBatch.Draw(videoTex, new Rectangle(0, 0, (int)screenDim.X, (int)screenDim.Y), Color.White);
                    spriteBatch.End();
                    break;
                case 2:
                    spriteBatch.Begin(SpriteBlendMode.None, SpriteSortMode.Immediate, SaveStateMode.SaveState);
                    {
                        // Apply the post process shader
                        postProcessEffect.Begin();
                        {
                            postProcessEffect.CurrentTechnique.Passes[0].Begin();
                            {
                                postProcessEffect.Parameters["fTimer"].SetValue((float)gameTime.TotalGameTime.TotalSeconds * 3.0f);
                                spriteBatch.Draw(videoTex, new Rectangle(0, 0, (int)screenDim.X, (int)screenDim.Y), Color.White);
                                postProcessEffect.CurrentTechnique.Passes[0].End();
                            }
                        }
                        postProcessEffect.End();
                    }
                    spriteBatch.End();
                    break;
                case 3:
                    float time = 0.5f * (float)gameTime.TotalGameTime.TotalSeconds;
                    Vector3 cameraPosition = new Vector3((float)Math.Sin(time), 0, (float)Math.Cos(time)) * 15.0f;

                    Matrix view = Matrix.CreateLookAt(cameraPosition, Vector3.Zero, Vector3.Up);
                    Matrix projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, GraphicsDevice.Viewport.AspectRatio, 1.0f, 1000.0f);
                    foreach (ModelMesh m in sphereModel.Meshes)
                    {
                        foreach (BasicEffect be in m.Effects)
                        {
                            be.World = Matrix.Identity;
                            be.View = view;
                            be.Projection = projection;

                            be.Texture = videoTex;
                            be.EnableDefaultLighting();
                            be.PreferPerPixelLighting = true;
                        }
                        m.Draw();
                    }
                    break;
                default:
                    break;
            }
        }
        public void SaveColorToFile(string fileName,Color[] data,int height,int width)
        {
            FileStream fs=new FileStream(fileName,FileMode.Create);
            StreamWriter sw=new StreamWriter(fs);
            
            for (int i = 0; i < height; i+=4)
            {
                for (int j = 0; j < width; j+=2)
                {
                    if (data[j + i*width].R > 150)
                        sw.Write("{0}", 1);
                    else
                        sw.Write("{0}", 0);
                }
                sw.WriteLine();
            }
            sw.Flush();
            fs.Flush();
            sw.Close();
            fs.Close();
        }
    }
}
